import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from yellowbrick.cluster import KElbowVisualizer
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import DBSCAN
from matplotlib.colors import ListedColormap
from sklearn import metrics

# 读取csv文件，以制表符分隔
df = pd.read_csv('marketing_campaign.csv', sep="\t")
# 删除缺失值
df.dropna(inplace=True)
# 将年份出生转换为年龄
df["Year_Birth"] = 2021 - df["Year_Birth"]
# 计算消费总和
df["Spent"] = df["MntWines"] + df["MntFruits"] + df["MntMeatProducts"] + df["MntFishProducts"] + df[
    "MntSweetProducts"] + df["MntGoldProds"]
# 重命名年龄列
df.rename(columns={'Year_Birth': 'Age'}, inplace=True)
# 将年份出生列重命名为年龄
y = df.drop(['Education', 'Marital_Status', 'Dt_Customer'], axis=1)

# 删除教育、婚姻状态和客户注册日期列
del_cols = ['AcceptedCmp3', 'AcceptedCmp4', 'AcceptedCmp5', 'AcceptedCmp1', 'AcceptedCmp2', 'Complain', 'Response']
ds = df.drop(del_cols, axis=1)

# 删除接受Cmp3-5列和投诉列
ds = pd.get_dummies(ds)
# 将ds中的分类变量转换为虚拟变量
scaler = StandardScaler()
scaler.fit(ds)
# 标准化数据
scaled_features = pd.DataFrame(scaler.transform(ds), columns=ds.columns)
# 主成分分析（PCA）是一种用于降低此类数据集的维度的技术，增加了可解释性，但同时最大限度地减少了信息损失。
# 将数据转换为3维
pca = PCA(n_components=3)
pca.fit(scaled_features)
# 使用PCA对数据进行降维
PCA_df = pd.DataFrame(pca.transform(scaled_features), columns=(["Education", "Income", "Kidhome"]))
# 将降维后的数据转换为DataFrame

print(scaled_features)
# 创建一个PCA模型，降维到3维
pca = PCA(n_components=3)
# 使用训练集训练模型
pca.fit(scaled_features)
# 将训练集降维到3维，并存储到PCA_df中
PCA_df = pd.DataFrame(pca.transform(scaled_features), columns=(["Education", "Income", "Kidhome"]))

print(scaled_features)

# 创建3个变量，分别存储降维后的x，y，z坐标
x = PCA_df["Education"]
y = PCA_df["Income"]
z = PCA_df["Kidhome"]

# 创建一个DBSCAN模型
model = DBSCAN(eps=1, min_samples=50,metric = "euclidean")
# 使用训练集训练模型
model.fit(PCA_df)
# 获取聚类结果
labels = model.labels_

# 将聚类结果添加到df中
df["Clusters"] = labels
# 统计每个聚类的样本数
cluster_counts = df['Clusters'].value_counts()

# 打印每个聚类的样本数
print(cluster_counts)

# 绘制聚类结果的柱状图
plt.figure(figsize=(8, 6))
sns.countplot(data=df, x='Clusters')
plt.title('Cluster Distribution')
plt.xlabel('Cluster')
plt.ylabel('Count')
plt.savefig("DBSCAN_Cluster_Distribution.png")
plt.show()

# 使用轮廓系数评估聚类质量
silhouette_score = metrics.silhouette_score(PCA_df, labels)
print("Silhouette Score:", silhouette_score)

# 使用Calinski-Harabasz指数评估聚类质量
ch_score = metrics.calinski_harabasz_score(PCA_df, labels)
print("Calinski-Harabasz Score:", ch_score)
